#ifndef LZWFilter_First
#ifdef __GNUG__
#pragma interface
#endif
#define LZWFilter_First

#include "StreamBuf.h"

#ifdef notdef
#define HSIZE           9001            /* 91% occupancy */
#define HSHIFT          (8-(16-13))
#else
#define HSIZE           5003            /* 80% occupancy */
#define HSHIFT          (8-(16-12))
#endif

#define MAXCODE(n)      ((1 << (n)) - 1)

/*
* The TIFF spec specifies that encoded bit strings range
* from 9 to 12 bits.  This is somewhat unfortunate in that
* experience indicates full color RGB pictures often need
* ~14 bits for reasonable compression.
*/
#define BITS_MIN        9               /* start with 9 bits */
#define BITS_MAX        12              /* max of 12 bit strings */

/* predefined codes */
#define CODE_CLEAR      256             /* code to clear string table */
#define CODE_EOI        257             /* end-of-information code */
#define CODE_FIRST      258             /* first free code entry */
#define CODE_MAX        MAXCODE(BITS_MAX)

class LZWFilter : public StreamBuf {
protected:
	long    lzw_bitoff;     /* bit offset into data */
	int     lzw_oldcode;    /* last code encountered */
	int     lzw_free_ent;   /* next free entry in hash table */
	u_short lzw_nbits;      /* number of bits/code */
	int     lzw_maxcode;    /* maximum code for lzw_nbits */
protected:
	LZWFilter();
};

class LZWDecoder: public LZWFilter {
protected:
	int     eof;
	short   prefixtab[HSIZE];           /* prefix(code) */
	u_char  suffixtab[CODE_MAX+1];      /* suffix(code) */
	u_char  stack[HSIZE-(CODE_MAX+1)];
	u_char  *lzw_stackp;                /* stack pointer */
	int     lzw_firstchar;              /* of string associated w/ last code */
	u_char  lzw_restart;                /* restart interrupted decode */

	int GetNextCode(void);

public:
	LZWDecoder();
	int LZWDecode(char*, int);
	int Underflow(u_char *bp, int size);
};

class LZWEncoder: public LZWFilter {
protected:
	char    tif_rawdata[3];
	u_long  tif_rawcc;
	long    lzw_bitsize;    /* size of strip in bits */
	long    checkpoint;             /* point at which to clear table */
#define CHECK_GAP       10000   /* ratio check interval */
	long    ratio;                  /* current compression ratio */
	long    incount;                /* (input) data bytes encoded */
	long    outcount;               /* encoded (output) bytes */
	long    htab[HSIZE];    /* hash table */
	short   codetab[HSIZE]; /* code table */

	void PutNextCode(int);
	void cl_block(void);
	void cl_hash(void);

public:
	LZWEncoder();
	void Close(void);
	int Overflow(u_char*, int);
};

#endif

